<template>
  <view :class="ns.b()">
    <i-biz-view
      v-if="isLoaded && hasAuthority"
      v-bind="$attrs"
      :key="key"
      :params="params"
      :context="context"
      :modelData="viewModel"
      :provider="provider"
      @redrawView="handleRedrawView"
    />
    <view v-else-if="!hasAuthority">403</view>
  </view>
</template>
<script lang="ts">
export default {
  options: {
    addGlobalClass: true,
    virtualHost: true,
    styleIsolation: "shared"
  }
}
</script>
<script setup lang="ts">
import { createUUID } from "qx-util";
import { IAppView } from "@ibiz/model-core";
import { isEmpty, isNil } from "ramda";
import { RuntimeError } from "@ibiz-template/core";
import {
  getViewProvider,
  IViewProvider,
  calcDynaSysParams,
  RedrawViewEvent,
} from "@ibiz-template/runtime";
import { useNamespace } from "@/use";
import { onMounted, PropType, Ref, ref, watch } from "vue";

const props = defineProps({
  context: { type: Object as PropType<IContext>, required: true },
  params: { type: Object as PropType<IParams> },
  modelData: { type: Object as PropType<IAppView> },
  viewId: { type: String },
});

const ns = useNamespace("view-shell");
const isLoaded: Ref<boolean> = ref(false);
const key: Ref<string> = ref(createUUID());
const errMsg: Ref<string> = ref("");
const provider: Ref<IViewProvider | undefined> = ref<IViewProvider>();
// 视图模型
const viewModel: Ref<IAppView | undefined> = ref<IAppView | undefined>();
// 权限
const hasAuthority: Ref<boolean> = ref(true);
// 当前视图上下文
const context: Ref<IContext> = ref(props.context);
// 当前视图参数
const params: Ref<IParams> = ref(props.params || {});

watch(
  () => ({ context: props.context, params: props.params }),
  (newVal) => {
    context.value = newVal.context;
    params.value = newVal.params ? newVal.params : {};
  }
);

/**
 * 初始化视图模型
 */
const initViewModel = async (): Promise<IAppView> => {
  return props.modelData
    ? props.modelData
    : await ibiz.hub.getAppView(props.viewId);
};

/**
 * 检查视图权限
 */
const checkViewAuthority = async (viewModel: IAppView): Promise<boolean> => {
  let checkResult: boolean = true;
  const { accUserMode, accessKey } = viewModel;
  const authInfo = ibiz.auth.getAuthInfo();
  // 0：未指定、 1：未登录用户、 2：登录用户、 3：未登录用户及登录用户、 4：登录用户且拥有指定资源能力
  if (accUserMode !== undefined) {
    switch (accUserMode) {
      case 1:
        if (authInfo) {
          checkResult = false;
        }
        break;
      case 2:
        if (!authInfo) {
          checkResult = false;
        }
        break;
      case 4:
        if (accessKey) {
          const app = await ibiz.hub.getApp(context.value.srfappid);
          const permitted = app.authority.calcByResCode(accessKey);
          if (!permitted) {
            checkResult = false;
          }
        }
        break;
      default:
        break;
    }
  }
  return checkResult;
};

/**
 * 计算视图模型
 */
const calcViewModel = async () => {
  const _viewModel = await initViewModel();
  if (!_viewModel) {
    throw new RuntimeError(ibiz.i18n.t("common.noFoundViewModel"));
  }
  // 检查权限
  hasAuthority.value = await checkViewAuthority(_viewModel);
  if (hasAuthority.value) {
    if (_viewModel.dynaSysMode === 1) {
      //* 计算实体资源路径上下文参数
      const appDataEntityId = _viewModel.appDataEntityId;
      if (!appDataEntityId) {
        throw new RuntimeError(
          ibiz.i18n.t("common.noSupportLoadingDynamic", {
            codeName: _viewModel.codeName,
          })
        );
      }

      /** 加载动态模型的请求参数 */
      const loadModelParams: IParams = await calcDynaSysParams(
        appDataEntityId,
        context.value,
        {
          viewParams: params,
          appId: _viewModel.appId,
        }
      );

      if (params.value.srfdatatype) {
        loadModelParams.srfdatatype = params.value.srfdatatype;
      }

      // 如果视图参数中存在 srfwftag 则直接使用视图参数
      if (params.value.srfwftag) {
        loadModelParams.srfwftag = params.value.srfwftag;
      } else if (appDataEntityId && _viewModel.enableWF) {
        // 处理数据请求的上下文
        // 存在主键则加载数据计算对应的参数
        if (loadModelParams.srfkey) {
          const noSrfSessionId =
            isNil(context.value.srfsessionid) ||
            isEmpty(context.value.srfsessionid);
          const id = createUUID();
          // 只要上下文中无 srfsessionid 则生成一个
          if (noSrfSessionId) {
            // 生成一个界面域，界面域标识为当前控制器实例的标识
            const domain = ibiz.uiDomainManager.create(id);
            context.value.srfsessionid = domain.id;
          }

          const app = ibiz.hub.getApp(_viewModel.appId);
          const service = await app.deService.getService(
            context.value,
            appDataEntityId!
          );
          const res = await service.get(context.value, params.value || {});
          if (res.ok && res.data) {
            const { srfwftag, processdefinitionkey, taskdefinitionkey } =
              res.data;
            if (srfwftag) {
              loadModelParams.srfwftag = srfwftag;
            }

            // *动态工作流编辑视图从数据里额外获取参数
            if (
              ["DEWFDYNAEDITVIEW3", "DEWFDYNAEDITVIEW"].includes(
                _viewModel.viewType!
              )
            ) {
              // 如果视图参数中没有获取到对应流程实例标识与步骤标识，则从请求回来的数据中获取对应信息
              if (isNil(params.value.processDefinitionKey)) {
                params.value.processDefinitionKey = processdefinitionkey;
              }
              if (isNil(params.value.taskDefinitionKey)) {
                params.value.taskDefinitionKey = taskdefinitionkey;
              }
            }
          }

          if (noSrfSessionId) {
            ibiz.uiDomainManager.destroy(id);
          }
        }
      }

      // *加载动态模型
      viewModel.value = await ibiz.hub.loadAppView(
        _viewModel.appId,
        _viewModel.id!,
        loadModelParams
      );
    } else {
      viewModel.value = _viewModel;
    }

    try {
      provider.value = await getViewProvider(_viewModel);
    } catch (error) {
      errMsg.value = error.message;
    } finally {
      isLoaded.value = true;
    }
  }
};

/**
 * 处理视图重绘
 */
const handleRedrawView = async (event: RedrawViewEvent): Promise<void> => {
  const { redrawData } = event;
  const { isReloadModel } = redrawData;
  // 合并参数
  Object.assign(context.value, redrawData.context);
  Object.assign(params.value, redrawData.params);
  if (isReloadModel) {
    await calcViewModel();
  }
  key.value = createUUID();
};

onMounted(() => {
  calcViewModel();
});
</script>
<style lang='scss'>
@include b('view-shell') {
  height: 100%;
}
</style>